Quickstart: Core SDK β‘οΈ
In this guide, we will create a smart account and mint an NFT with 0xGasless's SDK and Node.js.
For a detailed exploration of the SDK's inner workings, delve into our more granular API documentation.
1. Setup π οΈβ
Let's create a Typescript project using npm to get started. Let's start by adding some tooling:
mkdir 0xGasless-smartaccount && cd 0xGasless-smartaccount && bun init -y && bun i --save-dev @types/node tslib
π Then add 0xGasless's account package (with viem): π
bun i @0xgasless/smart-account viem
Create the following tsconfig.json (TypeScript config):
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"declaration": true,
"outDir": "./lib",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["./**/*.ts"]
}
The Account package will help you with creating Smart Account and an interface with them to send transactions. The same package can be used to also import the paymaster and bundler.
2. Create a Smart Account πβ
The Externally Owned Account (EOA) corresponding to the private key will serve as the owner of the Smart Account we create. You can get the private key from wallets like MetaMask, TrustWallet, Coinbase Wallet, etc. π
Create an index.ts file, copy the following code in it and replace the PRIVATE_KEY.
Be sure to never publicly expose your private key.
import {
Hex,
createWalletClient,
encodeFunctionData,
http,
parseAbi,
zeroAddress,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { polygonAmoy } from "viem/chains";
import { createSmartAccountClient } from "@0xgasless/smart-account";
const bundlerUrl =
"https://bundler.0xgasless.com/{chainId}"; // Found at https://dashboard.0xgasless.com/
export const createAccountAndMintNft = async () => {
// ----- 1. Generate EOA from private key
const account = privateKeyToAccount("0x" + "PRIVATE_KEY");
const client = createWalletClient({
account,
chain: polygonAmoy,
transport: http(),
});
const eoa = client.account.address;
console.log(`EOA address: ${eoa}`);
// ------ 2. Create 0xGasless smart account instance
const smartAccount = await createSmartAccountClient({
signer: client,
bundlerUrl,
});
const smartAccountAddress = await smartAccount.getAccountAddress();
console.log("Smart Account Address", smartAccountAddress);
};
createAccountAndMintNft();
Next, run the following command:
bun run index.ts
You should see EOA and the smart account address in the console.
bun i @0xgasless/smart-account viem
EOA address: 0x0723D1b47c4b9dE2edC65eC87299CC7D952986aC Smart Account Address 0x37E89f2b337c39188d6B6e6535E644326d779193
Smart accounts are designed with a pre-determined address known prior to deployment. Users transfer funds to this address and then the actual deployment transaction is internally batched with the first transaction that is done by that smart Account. Alternatively the paymaster could be used to sponsor this transaction.
Before continuing, now that we have our Smart Account address, we need to fund it with some test network tokens! Since we are using the Polygon Amoy network, head over to the Polygon Faucet, paste in your smart account address, and get some test tokens! If you skip this step, you might run into the AA21 didn't pay prefund error! πΈ
Once you have tokens available, follow the next steps.
3. Execute your first transaction πβ
Let's create your first transaction
- to: Smart Contract your Smart Account will interact with.
- data: For the mint function we will pass the nftData created using encodeFunctionData.
- value: For the mint function this won't be needed. Depending on the transaction, you can pass the value.
Add the following code in the script above at the bottom of the createAccountAndMintNft function.
try {
const nftAddress = "0xe7337B97F380A19A860068f0dACa74F50AF86548";
const parsedAbi = parseAbi(["function safeMint(address _to)"]);
const nftData = encodeFunctionData({
abi: parsedAbi,
functionName: "safeMint",
args: [smartAccountAddress as Hex],
});
// ------ 4. Send transaction
const userOpResponse = await smartAccount.sendTransaction({
to: nftAddress,
data: nftData,
});
const { transactionHash } = await userOpResponse.waitForTxHash();
console.log("transactionHash", transactionHash);
const userOpReceipt = await userOpResponse.wait();
if (userOpReceipt.success == "true") {
console.log("UserOp receipt", userOpReceipt);
console.log("Transaction receipt", userOpReceipt.receipt);
}
} catch (error: unknown) {
if (error instanceof Error) {
console.error("Transaction Error:", error.message);
}
}
- We create a transaction object.
- We send the transaction to our bundler.
- We store the response in a variable called transactionResponse.
- We retrieve the transaction detail by calling
userOpResponse.waitForTxHash()
.
To wait for a specific number of network confirmations before getting the value, use wait()
with a number argument. For instance, transactionResponse.wait(5)
waits for 5 confirmations before returning the value.
Check out the long transaction details available now in your console! You just created and executed your first userOps using the 0xGasless SDK. The entire 0xGasless crew is sending you a big round of applause! πππ»ππΌππ½ππΎππΏ
You can also view the latest transaction events on the Polygon Amoy Testnet Explorer.
View Complete Codeβ
import {
Hex,
createWalletClient,
encodeFunctionData,
http,
parseAbi,
zeroAddress,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { polygonAmoy } from "viem/chains";
import { createSmartAccountClient } from "@0xgasless/smart-account";
export const createAccountAndMintNft = async () => {
// ----- 1. Generate EOA from private key
const account = privateKeyToAccount("0x" + "PRIVATE_KEY");
const client = createWalletClient({
account,
chain: polygonAmoy,
transport: http(),
});
const eoa = client.account.address;
console.log(`EOA address: ${eoa}`);
// ------ 2. Create 0xGasless smart account instance
const smartAccount = await createSmartAccountClient({
signer: client,
bundlerUrl:
"https://bundler.0xgasless.com/{chainId}",
});
const smartAccountAddress = await smartAccount.getAccountAddress();
console.log("Smart Account Address", smartAccountAddress);
// ------ 3. Generate transaction data
const nftAddress = "0xe7337B97F380A19A860068f0dACa74F50AF86548";
const parsedAbi = parseAbi(["function safeMint(address _to)"]);
const nftData = encodeFunctionData({
abi: parsedAbi,
functionName: "safeMint",
args: [saAddress as Hex],
});
// ------ 4. Send transaction
const userOpResponse = await smartAccount.sendTransaction({
to: nftAddress,
data: nftData,
});
const { transactionHash } = await userOpResponse.waitForTxHash();
console.log("transactionHash", transactionHash);
const userOpReceipt = await userOpResponse.wait();
if (userOpReceipt.success == "true") {
console.log("UserOp receipt", userOpReceipt);
console.log("Transaction receipt", userOpReceipt.receipt);
}
};
createAccountAndMintNft();
If you run into any errors, check out troubleshooting for common errors.
π Congratulations on completing the quickstart!